# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-07-15 23:12
# File     : alpaca_adapter.py
# Project  : dynamic-portfolio-optimizer
# Desc     :
# src/data/adapters/alpaca_adapter.py
from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest, StockLatestQuoteRequest
from alpaca.data.timeframe import TimeFrame
from alpaca.trading.client import TradingClient
from typing import Dict, List, Any
import pandas as pd
from datetime import datetime
from .base_adapter import BaseDataAdapter, RateLimitDecorator


class AlpacaAdapter(BaseDataAdapter):
    """Alpaca数据适配器"""

    def __init__(self, config):
        super().__init__(config)
        self.data_client = StockHistoricalDataClient(
            api_key=config.api_key,
            secret_key=config.secret_key  # 需要在config中添加
        )
        self.trading_client = TradingClient(
            api_key=config.api_key,
            secret_key=config.secret_key
        )

    @RateLimitDecorator(calls=200, period=60)
    def get_stock_data(self, symbol: str, start_date: datetime,
                       end_date: datetime, interval: str = '1d') -> pd.DataFrame:
        """获取股票数据"""
        try:
            # 转换时间间隔
            timeframe_map = {
                '1m': TimeFrame.Minute,
                '5m': TimeFrame(5, TimeFrame.Unit.Minute),
                '1h': TimeFrame.Hour,
                '1d': TimeFrame.Day
            }

            timeframe = timeframe_map.get(interval, TimeFrame.Day)

            # 创建请求
            request_params = StockBarsRequest(
                symbol_or_symbols=[symbol],
                timeframe=timeframe,
                start=start_date,
                end=end_date
            )

            # 获取数据
            bars = self.data_client.get_stock_bars(request_params)

            if not bars.df.empty:
                data = bars.df.reset_index()
                data.set_index('timestamp', inplace=True)
                data['source'] = 'alpaca'

                return self.standardize_data(data)
            else:
                self.logger.warning(f"Alpaca: 未获取到{symbol}的数据")
                return pd.DataFrame()

        except Exception as e:
            self.logger.error(f"Alpaca获取股票数据失败: {e}")
            return pd.DataFrame()

    def get_options_data(self, symbol: str, expiration_date: datetime) -> pd.DataFrame:
        """获取期权数据 (Alpaca不支持期权数据)"""
        self.logger.info("Alpaca不支持期权数据")
        return pd.DataFrame()

    @RateLimitDecorator(calls=200, period=60)
    def get_fundamentals(self, symbol: str) -> Dict[str, Any]:
        """获取基本面数据"""
        try:
            # 获取资产信息
            asset = self.trading_client.get_asset(symbol)

            fundamentals = {
                'symbol': symbol,
                'company_name': asset.name,
                'exchange': asset.exchange,
                'asset_class': asset.asset_class,
                'status': asset.status,
                'tradable': asset.tradable,
                'marginable': asset.marginable,
                'shortable': asset.shortable,
                'source': 'alpaca'
            }

            return fundamentals

        except Exception as e:
            self.logger.error(f"Alpaca获取基本面数据失败: {e}")
            return {}

    def get_news(self, symbol: str, limit: int = 10) -> List[Dict[str, Any]]:
        """获取新闻数据"""
        try:
            # Alpaca新闻API
            news_request = {
                'symbols': symbol,
                'limit': limit,
                'sort': 'desc'
            }

            news_items = self.data_client.get_news(**news_request)

            processed_news = []
            for item in news_items:
                processed_news.append({
                    'symbol': symbol,
                    'title': item.headline,
                    'summary': item.summary,
                    'url': item.url,
                    'published_at': item.created_at,
                    'source': 'alpaca',
                    'author': item.author
                })

            return processed_news

        except Exception as e:
            self.logger.error(f"Alpaca获取新闻数据失败: {e}")
            return []
